package com.bnz.manager.service.impl;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphO;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.bnz.manager.service.SentinelService;
import org.springframework.stereotype.Service;

@Service
public class SentinelServiceImpl implements SentinelService {
    // 1. 获取资源的第一种方式,抛出异常的方式定义资源
    @Override
    public String getRest() {
        // 1.5.0 版本开始可以利用 try-with-resources 特性（使用有限制）
        // 资源名可使用任意有业务语义的字符串，比如方法名、接口名或其它可唯一标识的字符串。
        try (Entry entry = SphU.entry("Sentinelrest1")) {
            // 被保护的业务逻辑
            // do something here...
            System.out.println("获取资源的第一种方式！抛出异常的方式定义资源！");
        } catch (BlockException ex) {
            // 资源访问阻止，被限流或被降级
            // 在此处进行相应的处理操作
            ex.printStackTrace();
            return "出现了限流异常，使用抛出异常的方式定义资源！";
        }
        return "success1";
    }

    // 2. 获取资源的第二种方式,返回布尔值方式定义资源
    @Override
    public String getRest2() {
        // 资源名可使用任意有业务语义的字符串
        if (SphO.entry("Sentinelrest2")) {
            // 务必保证finally会被执行
            try {
                /**
                 * 被保护的业务逻辑
                 */
                System.out.println("获取资源的第二种方式,返回布尔值方式定义资源！");
            } finally {
                SphO.exit();
            }
        } else {
            // 资源访问阻止，被限流或被降级
            // 进行相应的处理操作
            return "出现了限流异常，使用布尔值方式定义资源！";
        }
        return "success2";
    }

    // 3. 获取资源的第三种方式,注解方式定义资源（最重要也是最常用的）
    // 3.1 使用blockHandler，处理函数和资源所在方法在同一个类中（处理BlockException）
    //    @SentinelResource(value = "Sentinelrest3",blockHandler = "mySRHandler")
    // 3.2 使用blockHandlerClass，处理函数和资源所在方法可以不在同一个类中，但是在实现类中必须加static（处理BlockException）
    //    @SentinelResource(value = "Sentinelrest3",blockHandler = "mySRHandler2",blockHandlerClass = MySentinelResourceHandler.class)
    // 3.3 使用fallback处理其他的异常（用来处理其他的异常）
    //    @SentinelResource(value = "Sentinelrest3",fallback = "mySROtherHandler")
    // 3.4 使用fallbackClass处理其他的异常（用来处理其他的异常），同样在实现类中必须加static
    @SentinelResource(value = "Sentinelrest3",fallback = "mySROtherHandler2",fallbackClass = mySROtherHandler.class)
    @Override
    public String getRest3() {
        return "success3";
    }
    public String mySRHandler(BlockException ex) {
        return "出现了限流异常，注解方式定义资源（在同一个类中）！";
    }
    public String mySROtherHandler(Throwable tw) {
        return "出现了未知异常，注解方式定义资源（使用fallback处理所有异常）！";
    }
}
